package core;

import java.util.ArrayList;
import java.util.List;

import card.BuildingCard;
import card.Card;
import card.CreatureCard;
import card.LandCard;

/**
 * 
 * @author Anton
 *
 *A single square on the map, which can contain one landcard, one building, and several creatures.
 */
public class Tile {

	private static int MAXCREATURESONTILE=Constants.MAXCREATURESONTILE, MAXBUILDINGSONTILE=Constants.MAXBUILDINGSONTILE, CREATUREROOM=Constants.CREATUREROOM;
	
	private CreatureCard creature[] = new CreatureCard[MAXCREATURESONTILE];
	private LandCard land;
	private BuildingCard building[] = new BuildingCard[MAXBUILDINGSONTILE];

	/** The player that gains resources from the tile. Does not require a CreatureCard on the tile **/
	private Player owningPlayer;
	
	/**
	 * returns the first creaturecard on the tile.
	 * @return
	 */
	public CreatureCard getCreature(int i){
		return creature[i];
	}
	
	public CreatureCard getFirstCreature(){
		return creature[0];
	}
	
	public BuildingCard getFirstBuilding(){
		return building[0];
	}
	
	/**
	 * Returns a new list of all creatures on the tile.
	 * @return
	 */
	public List<CreatureCard> getCreatures(){
		List<CreatureCard> l = new ArrayList<CreatureCard>();
		for(CreatureCard c : creature){
			if(c != null)
				l.add(c);
		}
		return l;
	}
	
	/**
	 * Returns true if there's room for the creature to be placed on the tile.
	 * @param newCreature
	 * @return
	 */
	public boolean hasRoomFor(CreatureCard newCreature){
		if(getCreatures().size() >= MAXCREATURESONTILE){ 
			return false;
		}
		int spaceTaken = 0;
		List<CreatureCard> checkedCreatures = getCreatures();
		checkedCreatures.add(newCreature);
		
		for(CreatureCard c : checkedCreatures){
			switch(c.getSize()){
			case small:
				spaceTaken += 1;
				break;
			case normal:
				spaceTaken += 2;
				break;
			case large:
				spaceTaken += 3;
				break;
			case huge:
				spaceTaken += 4;
				break;
			default:
				spaceTaken += 2;
				break;
			}
		}
		if(spaceTaken <= CREATUREROOM)
			return true;
		else
			return false;
		
	}
	
	public boolean hasRoomFor(BuildingCard card){
		if(getBuildings().size() < MAXBUILDINGSONTILE)
			return true;
		else
			return false;
	}
	
	/**
	 * Returns a list of all buildings on the tile.
	 * @return
	 */
	public List<BuildingCard> getBuildings(){
		List<BuildingCard> l = new ArrayList<BuildingCard>();
		for(BuildingCard c : building){
			if(c != null)
				l.add(c);
		}
		return l;	
	}
	/**
	 * Returns a list of all Cards on the tile.
	 * @return
	 */
	public List<Card> getAllCards(){
		List<Card> l = new ArrayList<Card>();
		l.addAll(getCreatures());
		l.addAll(getBuildings());
		l.add(land);
		return l;
	}
	
	public void addCreature(CreatureCard c){
		for (int i=0; i<MAXCREATURESONTILE; i++)
			if(creature[i] == null){
				creature[i]=c;
				break;
			}
		//TODO case tile is full
	}

	public void addBuilding(BuildingCard c){
		for (int i=0; i<MAXBUILDINGSONTILE; i++)
			if(building[i] == null){
				building[i]=c;
				break;
			}
		//TODO case tile is full
	}
	/**
	 * Overwrites old lands.
	 * @param c
	 */
	public void setLandCard(LandCard c){
		land=c;
	}
	public LandCard getLandCard(){
		return land;
	}
	
	/**
	 * remove all cards which are the exact same card as parameter.
	 * @param card
	 */
	public void removeCard(Card card){
		for(int i = 0; i<MAXCREATURESONTILE; i++){
			if(creature[i]==card){
				creature[i]=null;
				fixOrderOfCreatures();
			}
		}
		for(int i = 0; i<MAXBUILDINGSONTILE; i++){
			if(building[i]==card){
				building[i]=null;
			}
		}
		if(land==card){
			land=null;
		}
	}
	
	/**
	 * removes gaps in the array creature
	 */
	private void fixOrderOfCreatures(){
		for(int i=0; i<MAXCREATURESONTILE; i++){
			if(creature[i]==null){
				for(int c=i; c<MAXCREATURESONTILE-1; c++){
					creature[c]=creature[c+1];
				}
				creature[MAXCREATURESONTILE-1] = null;
			}				
		}
	}
	
	/**
	 * returns true if the given card is positioned on this tile
	 * @param card
	 * @return
	 */
	public boolean contains(Card card){
		for(Card c : creature){
			if(card==c){
				return true;
			}
		}
		for(Card b : building){
			if(card==b){
				return true;
			}
		}
		if(card==land)
			return true;
		return false;
	}
	
	/**
	 * Sets the player that owns and gains resources from this tile.
	 * @param p
	 */
	public void setOwningPlayer(Player p){
		owningPlayer = p;
	}
	/**
	 * returns the player who owns and is gaining resources from the tile.
	 * @return
	 */
	public Player getOwningPlayer(){
		return owningPlayer;
	}
	/**
	 * Returns the player who has CreatureCards on the tile and therefore is blocking movement to the tile.
	 * Returns null if no CreatureCards are on the tile.
	 * @return
	 */
	public Player getOccupyingPlayer(){
		if(getFirstCreature() != null)
			return getFirstCreature().getOwner();
		else
			return null;
	}
	
	public int getGoldIncome(){
		int goldIncome=0;
		if(land != null)
			goldIncome += land.getGoldIncome();
		for(BuildingCard b : getBuildings()){
			goldIncome += b.getGoldIncome();
		}
		return goldIncome;
	}
	public int getManaIncome(){
		int manaIncome=0;
		if(land != null)
			manaIncome += land.getManaIncome();
		for(BuildingCard b : getBuildings()){
			manaIncome += b.getManaIncome();
		}
		return manaIncome;
	}
}
